package vigenere;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;



public class Kasiski {

	public static double ic (String texte, int longueur) {
		// Calcul de l'indice de coïncidence d'une ligne de texte
		int[] m = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // Tableau des ocurrences de chaque caractère
		char caractere;
		for (int i = 0 ; i < longueur ; i++) {
			// remplir le tableau m
			caractere = texte.charAt(i);
			m[Character.getNumericValue(caractere)-10]++;
		}
		double ic = 0;
		for (int i=0 ; i<25 ; i++) {
			ic = ic + m[i]*(m[i]-1);
		}
		ic = ic/(longueur*(longueur-1));
		return ic;
	}
	
	public static double icMutuelle (String x, String y) {
		int[] mx = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
		int[] my = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};		
		char caractereX;
		int lX = x.length();
		for (int i = 0 ; i < lX ; i++) {
			// remplir le tableau m
			caractereX = x.charAt(i);
			mx[Character.getNumericValue(caractereX)-10]++;
		}
		char caractereY;
		int lY = y.length();
		for (int i = 0 ; i < lY ; i++) {
			// remplir le tableau m
			caractereY = y.charAt(i);
			my[Character.getNumericValue(caractereY)-10]++;
		}
		double ic = 0;
		for (int i=0 ; i<25 ; i++) {
			ic = ic + mx[i]*my[i];
		}
		ic = ic/(lX*lY);
		return ic;
	}
	
	public static String decaler(String chaine) {
		int l = chaine.length();
		String alphabet = "abcdefghijklmnopqrstuvwxyz";
		String chaineRslt = "";
		for (int i = 0 ; i < l ; i++) {
			if ((chaine.charAt(i)+"").equals("z")) {
				chaineRslt += "a";
			} else {
				chaineRslt += alphabet.charAt(Character.getNumericValue(chaine.charAt(i)) - 9);
			}
		}
		return chaineRslt;
	}
	
	public static String findKey(String texte, int n) {
		int l = texte.length();
		int[] cle = new int[n];
		int[] nbCar;
		int valeurMax;
		int indexValeurMax;
		int index;
		int codeAsciiLettre;
		int carCle;
		int aAscii = 97;
		int eAscii = 101;
		int zAscii = 122;
		for(int i = 0 ; i < n ; i++) {
			index = i;
			codeAsciiLettre = 0;
			nbCar = new int[26];
			valeurMax = -1;
			indexValeurMax = -1;
			while(index < l) {
				codeAsciiLettre = (int) texte.charAt(index);
				nbCar[codeAsciiLettre - 97]++;
				index += n;
			}
			for(int j = 0 ; j < 26 ; j++) {
				if(nbCar[j] > valeurMax) {
					valeurMax = nbCar[j];
					indexValeurMax = j;
				}
			}
			carCle = indexValeurMax + 97;
			if(carCle < eAscii) {
				cle[i] = zAscii - (eAscii - carCle) + 1;
			} else {
				cle[i] = aAscii + (carCle - eAscii);			
			}
		}
		// A ce stade : clé est finalisé, donc on le caste
		String cleFinal = "";
		for(int i = 0 ; i < n ; i++) {
			cleFinal += (char) cle[i];
		}
		//System.out.println("Clé : " + cleFinal);
		return cleFinal;
	}
	
	public static void decrypter(String fileIn, String fileOut, int indiceLangue) {
		try {
			// Ouverture du fichier à lire
			FileReader fr = new FileReader(fileIn);
			BufferedReader br = new BufferedReader(fr);
			
			// Construction de la string contenant la totalité du texte (une ligne sans espace)
			String texte = "";
			int caractereInt = br.read();
			while (caractereInt != -1) {
				if (caractereInt != 10 && caractereInt != 32) {
					texte = texte + (char) caractereInt;
				}
				caractereInt = br.read();
			}
			int l = texte.length(); // Récupération de la longueur de la string
			System.out.println("Texte à décrypter, condensé : extrait");
			System.out.println(texte);
			System.out.println(l);
			
			// Fermeture du fichier à lire
			fr.close();
			
			// Maximisation de l'indice de coincidence pour k in [1 ; l/4]
			// Estimation de la longueur de la clé par formule 
			// (Référence : http://www.bibmath.net/crypto/poly/viganalyse.php3)
			double[] icLangue = new double[2];
			icLangue[0] = 0.074;
			icLangue[1] = 0.0667;
			int lCleEstimee = (int) (((icLangue[indiceLangue]-0.038)*l)/((l-1)*ic(texte,l) - l*0.038 + icLangue[indiceLangue]));
			System.out.println("Longueur de clé estimée par formule : " + lCleEstimee);
			int kMax = 1;
			double icMax = 0;
			for (int k = 1 ; k < l/4 ; k++) {
				// Extraction de la sous-chaine
				String c = "";
				int i = 0;
				int lSsChaine = 0;
				while (k*i < l) {
					c = c + texte.charAt(k*i);
					lSsChaine++;
					i++;
				}
				// Calcul de l'indice de coincidence
				double icSsChaine = ic(c,lSsChaine);
				// L'IC est-il max ?
				if (icSsChaine > icMax) {
					kMax = k;
					icMax = icSsChaine;
					System.out.println("Nouveau kMax : " + kMax);
				}
			}
			
			// kMax est la longueur de la clé. Mise en conformité avec le sujet
//			int n = lCleEstimee;
//			int n = 8;
//			String cle = findKey(texte, n);
			
			
			// Proposition de clés possibles
			String[] cle = new String[Math.abs(lCleEstimee) + 4];
			System.out.println("Votre serviteur vous propose les clés suivantes :");
			for (int n = 0 ; n < Math.abs(lCleEstimee) + 4 ; n++) {
				cle[n] = findKey(texte, n);
				System.out.println(n + " : " + cle[n]);
			}
			String inputLine = null;
			try {
				BufferedReader buffer = new BufferedReader (
						new InputStreamReader ( System.in ));
				inputLine = buffer.readLine();
			}
			catch (IOException e) {
				System. out. println ( " IOException : " + e );
			}
			String cleFinale = cle[Integer.parseInt(inputLine)];
			
			// Réécriture dans le fichier (utilisation de la fonction de décodage de vigenere)
			Vigenere.operation("d", fileIn, fileOut, cleFinale);
			
			// L'utilisateur est-il content ?
			boolean utilisateurContent = false;
			while(!utilisateurContent) {
				System.out.print("Etes-vous satisfait Maître ? (o/n) ");
				String content = null;
				try {
					BufferedReader buffer = new BufferedReader (
							new InputStreamReader ( System.in ));
					content = buffer.readLine();
				}
				catch (IOException e) {
					System. out. println ( " IOException : " + e );
				}
				if(content.equals("o")) {
					utilisateurContent = true;
					System.out.println("Je suis heureux de vous avoir satisfait maître");
				} else {
					// Fouet du serviteur
					System.out.println("Pardon mon maître, je vous ai déçu, appuyez sur entrer pour me fouetter");
					try {
						BufferedReader buffer = new BufferedReader (
								new InputStreamReader ( System.in ));
						inputLine = buffer.readLine();
					}
					catch (IOException e) {
						System. out. println ( " IOException : " + e );
					}
					// Proposition de clés possibles
					for (int n = 0 ; n < Math.abs(lCleEstimee) + 2 ; n++) {
						System.out.println(n + " : " + cle[n]);
					}
					inputLine = null;
					try {
						BufferedReader buffer = new BufferedReader (
								new InputStreamReader ( System.in ));
						inputLine = buffer.readLine();
					}
					catch (IOException e) {
						System. out. println ( " IOException : " + e );
					}
					cleFinale = cle[Integer.parseInt(inputLine)];
					
					// Réécriture dans le fichier (utilisation de la fonction de décodage de vigenere)
					Vigenere.operation("d", fileIn, fileOut, cleFinale);
				}
			}

		}
		catch (FileNotFoundException e) {
			System.out.println("Fichier non trouvé");
		}
		catch (IOException e) {
			System.out.println("Erreur lors de l'ouverture du fichier");
		}
	}
	
}
